/*
 * SphinxQueryData.h
 *
 *  Created on: 2011-10-8
 *      Author: hontlong
 */

#ifndef SPHINXQUERYDATA_H_
#define SPHINXQUERYDATA_H_

/**
 * 从输入解析的查询数据
 */
class QueryData
{
public:
	QueryData() :
		start(0), maxquerytime(0)
	{
		rows = 20;
		retries = 0;
		connecttimeout = 0;
		//		matchmode = "";
		//		rankingmode = "";
		//		sortmode = "";
	}

	string index;
	string q;
	list<string> filters;
	//idrange=minId,maxId
	string idrange;
	int start;
	int rows;
	string fieldweights;
	int retries;
	int maxquerytime;
	int connecttimeout;
	string groupby;
	string groupdistinct;
	string matchmode;
	string rankingmode;
	string sortmode;
	string select;
};


/**
 * 可以应用于Sphinx接口的查询数据
 */
class SphinxQueryData
{
public:
	struct Filter
	{
		Filter()
		{
			values_num = 0;
			exclude = false;
		}
		~Filter()
		{
		}
		enum Type
		{
			kValue, kIntRange, kFloatRange
		};
		static const int kMaxValueNum = 100;
		Type type;
		string attr_name;
		bool exclude;
		int values_num;
		sphinx_int64_t values[kMaxValueNum];//100,最多限定
		int int_min;
		int int_max;
		float float_min;
		float float_max;
	};

	SphinxQueryData(QueryData qd)
	{
		//TODO 查询的二次转换，细节解析和检查
		//TODO 已经处理全Key,但还需要细化
		index = qd.index;
		q = qd.q;
		//过滤器
		//filter - 属性值，属性范围，属性范围float
		//filters = qd.filters;
		{
			list<string>::iterator it = qd.filters.begin();
			//filter=attr:a,b,c,d
			//filter=!attr:a,b,c,d
			//filter=attr:[a TO b]
			//filter=!attr:[a TO b]
			//TODO 过滤器仅支持上述4种写法不支持小括号
			for (; it != qd.filters.end(); ++it)
			{
				string temp_filter = *it;
				Filter filter;
				if (it->at(0) == '!')
				{
					filter.exclude = true;
				}
				string::size_type p = it->find(':');
				if (p == string::npos)
				{
					throw "filters 错误的格式";
				}
				string::size_type s = filter.exclude ? 1 : 0;
				filter.attr_name = it->substr(s, p - s);
				++p;
				for (; p < it->size() && it->at(p) == ' '; ++p)
					;//p前进到第一个非空值
				if (p >= it->size())
				{
					throw "filters 错误的格式";
				}
				if (it->at(p) == '[')
				{
					filter.type = SphinxQueryData::Filter::kIntRange;
					for (string::size_type t = p + 1; t < it->size(); ++t)
					{
						if (it->at(t) == '.')
						{//小数点，判定是否是float类型
							filter.type = SphinxQueryData::Filter::kFloatRange;
							break;
						}
					}
					++p;//跳过[
					for (; p < it->size() && it->at(p) == ' '; ++p)
						;//p前进到第一个非空值
					s = p;
					p = it->find("TO", s);
					if (p == string::npos)
					{
						throw "filters 错误的格式";
					}
					string::size_type e = it->size() - 1;//结束位置
					for (; e > 0 && (it->at(e) == ' ' || it->at(e) == ']'); --e)
						;//跳过最后的空格和]
					if (p >= e)
					{
						throw "filters 错误的格式";
					}
					if (filter.type == SphinxQueryData::Filter::kIntRange)
					{
						string temp(it->substr(s, p - s));
						filter.int_min = atoi(trim(temp).c_str());
						if (e <= p + 2)
						{//跳过TO
							throw "filters 错误的格式";
						}
						temp = it->substr(p + 2, e + 1 - (p + 2));
						filter.int_max = atoi(trim(temp).c_str());
					}
					else
					{//float
						string temp(it->substr(s, p - s));
						filter.float_min = atof(trim(temp).c_str());
						temp = it->substr(p + 2, e - (p + 2));
						filter.float_max = atof(trim(temp).c_str());
					}
				}
				else
				{
					filter.type = SphinxQueryData::Filter::kValue;
					//filter=attr:a,b,c,d //filter=!attr:a,b,c,d
					s = p;//第一个非空值
					for (; (p = it->find(',', s)) != string::npos; s = p + 1)
					{
						if (p <= s)
						{
							throw "filters 错误的格式";
						}
						string temp_value = it->substr(s, p - s);
						//TODO tofix 不必要求必须是数字
						if (temp_value.end() != find_if(temp_value.begin(),
								temp_value.end(), not1(ptr_fun(::isdigit))))
						{
							throw "filters 错误的格式,属性值必须是数字.";
						}
						filter.values[filter.values_num] = atoi(
								temp_value.c_str());
						filter.values_num++;
						if (filter.values_num
								>= SphinxQueryData::Filter::kMaxValueNum)
						{
							break;
						}
					}
					if (filter.values_num < 100 && s < it->size())
					{
						filter.values[filter.values_num] = atoi(
								it->substr(s).c_str());
						filter.values_num++;
					}
				}
				//过滤器组装完毕
				filters.push_back(filter);
			}
		}

		//idrange
		idrange_min = 0L;
		idrange_max = 0L;

		if (qd.idrange.size() > 0)
		{
			string::size_type p = qd.idrange.find_first_of(',', 0);
			if (p != string::npos)
			{
				idrange_min = atol(qd.idrange.substr(0, p).c_str());
				idrange_max = atol(qd.idrange.substr(p + 1).c_str());
			}
		}
		start = qd.start;
		rows = qd.rows;
		//fieldweight - 字段数，字段名数组，权重数组（整数）
		//fieldweights=fieldName1:1,fieldName2:5
		fieldweights = qd.fieldweights;
		fieldweights_num = 0;
		fieldweights_fields = NULL;
		fieldweights_weights = NULL;
		if (qd.fieldweights.size() > 0)
		{
			string::iterator it;
			for (it = qd.fieldweights.begin(); it < qd.fieldweights.end(); it++)
			{
				if (*it == ',')
				{
					fieldweights_num++;
				}
			}
			if (qd.fieldweights[qd.fieldweights.size() - 1] != ',')
			{
				fieldweights_num++;
			}
			fieldweights_fields = new const char*[fieldweights_num];
			fieldweights_weights = new int[fieldweights_num];

			string::size_type s = -1;
			string::size_type e = -1;
			for (int i = 0; i < fieldweights_num; i++)
			{
				s = e + 1;
				e = qd.fieldweights.find_first_of(',', s);

				string::size_type p = qd.fieldweights.find_first_of(':', s);
				if (p == string::npos)
				{
					//error!
					throw "fieldweights 错误的格式";
				}

				string f = trim(qd.fieldweights.substr(s, p - s));
				char * p_field_temp = new char[f.size() + 1];
				strncpy(p_field_temp, f.c_str(), f.size());
				p_field_temp[f.size()] = 0;
				fieldweights_fields[i] = p_field_temp;

				if (e != string::npos)
				{
					string w = trim(qd.fieldweights.substr(p + 1, e - (p + 1)));
					fieldweights_weights[i] = atoi(w.c_str());
				}
				else
				{
					string w = trim(qd.fieldweights.substr(p + 1));
					fieldweights_weights[i] = atoi(w.c_str());
				}
			}
		}

		retries = qd.retries;
		maxquerytime = qd.maxquerytime;
		connecttimeout = qd.connecttimeout;

		//groupby
		//groupby= SPH_GROUPBY_ATTR:attrName:@group desc.
		groupby = qd.groupby;
		groupby_func = SPH_GROUPBY_ATTR;
		groupby_attr = "";//用于决定是否设定了
		groupby_sort = "@group desc";
		if (qd.groupby.size() > 0)
		{
			string::size_type split1 = qd.groupby.find(':', 0);
			if (split1 != string::npos)
			{
				string func_name = qd.groupby.substr(0, split1);
				map<string, int> groupby_map;
				groupby_map["SPH_GROUPBY_DAY"] = SPH_GROUPBY_DAY;
				groupby_map["SPH_GROUPBY_WEEK"] = SPH_GROUPBY_WEEK;
				groupby_map["SPH_GROUPBY_MONTH"] = SPH_GROUPBY_MONTH;
				groupby_map["SPH_GROUPBY_YEAR"] = SPH_GROUPBY_YEAR;
				groupby_map["SPH_GROUPBY_ATTR"] = SPH_GROUPBY_ATTR;

				map<string, int>::iterator it = groupby_map.find(func_name);
				if (it == groupby_map.end())
				{
					throw "groupby 错误的格式";
				}
				groupby_func = it->second;

				string::size_type split2 = qd.groupby.find(':', split1 + 1);
				if (split2 != string::npos)
				{
					groupby_attr = qd.groupby.substr(split1 + 1, split2
							- (split1 + 1));
					groupby_sort = qd.groupby.substr(split2 + 1);
				}
				else
				{
					if (groupby_func == SPH_GROUPBY_ATTR)
					{
						//必须指定第三个参数
						throw "groupby 错误的格式";
					}
					groupby_attr = qd.groupby.substr(split1 + 1);
				}
			}
		}

		//groupdistinct
		groupdistinct = qd.groupdistinct;

		//匹配模式
		if (qd.matchmode == "SPH_MATCH_ALL")
		{
			matchmode = SPH_MATCH_ALL;
		}
		else if (qd.matchmode == "SPH_MATCH_ANY")
		{
			matchmode = SPH_MATCH_ANY;
		}
		else if (qd.matchmode == "SPH_MATCH_PHRASE")
		{
			matchmode = SPH_MATCH_PHRASE;
		}
		else if (qd.matchmode == "SPH_MATCH_BOOLEAN")
		{
			matchmode = SPH_MATCH_BOOLEAN;
		}
		else if (qd.matchmode == "SPH_MATCH_EXTENDED")
		{
			matchmode = SPH_MATCH_EXTENDED;
		}
		else if (qd.matchmode == "SPH_MATCH_FULLSCAN")
		{
			matchmode = SPH_MATCH_FULLSCAN;
		}
		else if (qd.matchmode == "SPH_MATCH_EXTENDED2")
		{
			matchmode = SPH_MATCH_EXTENDED2;
		}
		else
		{
			throw "matchmode is error![" + qd.matchmode + "]";
		}

		//评分方式
		if (qd.rankingmode == "SPH_RANK_PROXIMITY_BM25")
		{
			rankingmode = SPH_RANK_PROXIMITY_BM25;
		}
		else if (qd.rankingmode == "SPH_RANK_BM25")
		{
			rankingmode = SPH_RANK_BM25;
		}
		else if (qd.rankingmode == "SPH_RANK_NONE")
		{
			rankingmode = SPH_RANK_NONE;
		}
		else if (qd.rankingmode == "SPH_RANK_WORDCOUNT")
		{
			rankingmode = SPH_RANK_WORDCOUNT;
		}
		else
		{
			throw "rankingmode is error![" + qd.rankingmode + "]";
		}

		//排序模式
		string strSortMode;
		string::size_type loc1 = qd.sortmode.find(":", 0);

		if (loc1 == string::npos)
		{
			strSortMode = qd.sortmode;
			sortclause = "";
		}
		else
		{
			strSortMode = qd.sortmode.substr(0, loc1);
			sortclause = qd.sortmode.substr(loc1 + 1);
		}

		if (strSortMode == "SPH_SORT_RELEVANCE")
		{
			sortmode = SPH_SORT_RELEVANCE;
		}
		else if (strSortMode == "SPH_SORT_ATTR_DESC")
		{
			sortmode = SPH_SORT_ATTR_DESC;
		}
		else if (strSortMode == "SPH_SORT_ATTR_ASC")
		{
			sortmode = SPH_SORT_ATTR_ASC;
		}
		else if (strSortMode == "SPH_SORT_TIME_SEGMENTS")
		{
			sortmode = SPH_SORT_TIME_SEGMENTS;
		}
		else if (strSortMode == "SPH_SORT_EXTENDED")
		{
			sortmode = SPH_SORT_EXTENDED;
		}
		else if (strSortMode == "SPH_SORT_EXPR")
		{
			sortmode = SPH_SORT_EXPR;
		}
		else
		{
			throw "strSortMode is error![" + strSortMode + "]";
		}
		//select
		select = qd.select;
	}

	~SphinxQueryData()
	{
		if (fieldweights_weights != NULL)
		{
			delete fieldweights_weights;
		}
		if (fieldweights_fields != NULL)
		{
			//fieldweights_fields = new const char*[fieldweights_num];
			for (int i = 0; i < fieldweights_num; i++)
			{
				if (fieldweights_fields[i] != NULL)
				{
					delete fieldweights_fields[i];
				}
			}
			delete fieldweights_fields;
		}
	}

	string index;
	string q;

	//list<string> filters;
	list<Filter> filters;

	int start;
	int rows;

	long long idrange_min;
	long long idrange_max;
	//fieldweight - 字段数，字段名数组，权重数组（整数）
	string fieldweights;
	int fieldweights_num;
	const char ** fieldweights_fields;
	int * fieldweights_weights;

	int retries;
	int maxquerytime;
	int connecttimeout;
	string groupby;
	int groupby_func;
	string groupby_attr;//用于决定是否设定了
	string groupby_sort;
	string groupdistinct;
	int matchmode;
	int rankingmode;
	int sortmode;
	string sortclause;
	string select;

};

#endif /* SPHINXQUERYDATA_H_ */
